package com.zlx.mall.biz.trolley.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.zlx.mall.base.entity.ScComboCategory;
import com.zlx.mall.base.entity.ScGoods;
import com.zlx.mall.base.entity.ScGoodsOrder;
import com.zlx.mall.base.entity.ScTrolley;
import com.zlx.mall.base.service.*;
import com.zlx.mall.basic.common.enums.NotDeteteEnum;
import com.zlx.mall.basic.common.exception.IllegalBizArgumentException;
import com.zlx.mall.basic.common.exception.IllegalBizStatusException;
import com.zlx.mall.basic.datasource.enums.StatusEnum;
import com.zlx.mall.biz.combo.model.GoodsUpgradeResponse;
import com.zlx.mall.biz.combo.service.IComboService;
import com.zlx.mall.biz.goods.enums.GoodsTypeEnum;
import com.zlx.mall.biz.order.enums.OrderStatusEnum;
import com.zlx.mall.biz.trolley.model.AddTrolleyRequest;
import com.zlx.mall.biz.trolley.model.TrolleyListResponse;
import com.zlx.mall.biz.trolley.service.ITrolleyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author xiatian
 * @Date 2025/3/23 星期日 18:17
 * @注释
 */
@Slf4j
@Service
public class TrolleyServiceImpl implements ITrolleyService {
    @Autowired
    private IScTrolleyService scTrolleyService;
    @Autowired
    private IScGoodsService scGoodsService;
    @Autowired
    private IScCategoryService scCategoryService;
    @Autowired
    private IScComboCategoryService scComboCategoryService;
    @Autowired
    private IComboService comboService;
    @Autowired
    private IScGoodsOrderService scGoodsOrderService;


    @Override
    public void addTrolley(AddTrolleyRequest request) {
        List<ScGoodsOrder> orders = scGoodsOrderService.list(new QueryWrapper<ScGoodsOrder>().eq(ScGoodsOrder.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScGoodsOrder.USER_ID, request.getUserId()).ne(ScGoodsOrder.STATUS, OrderStatusEnum.CANCEL.getCode()));
        if(CollUtil.isNotEmpty(orders)) throw new IllegalBizStatusException("您已提交过订单，请前去我的订单查看");

        int number = request.getNumber();
        ScGoods scGoods = Optional.ofNullable(scGoodsService.getOne(new QueryWrapper<ScGoods>().eq(ScGoods.ID, request.getGoodsId()).eq(ScGoods.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScGoods.STATUS, StatusEnum.ENABLE.getIntegerValue())))
                .orElseThrow(() -> new IllegalBizArgumentException("商品不存在"));

        ScTrolley scTrolley = null;
        if (!GoodsTypeEnum.MATCH.getCode().equals(request.getType())) { //套餐商品
            List<Long> comboGoodsIds = scComboCategoryService.list(new QueryWrapper<ScComboCategory>()
                            .eq(ScComboCategory.SUB_CATEGORY_ID, request.getSubCategoryId())
                            .eq(ScComboCategory.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()))
                    .stream().map(ScComboCategory::getGoodsId).collect(Collectors.toList());
            List<Long> upgradeGoodsIds = comboService.goodsUpgrade(request.getSubCategoryId())
                    .stream().map(GoodsUpgradeResponse::getId).collect(Collectors.toList());
            comboGoodsIds.addAll(upgradeGoodsIds);
            log.info("二级类目套餐={}下包含升级的商品列表",comboGoodsIds);
            scTrolley = scTrolleyService.getOne(new QueryWrapper<ScTrolley>()
                    .eq(ScTrolley.USER_ID, request.getUserId())
                    .in(ScTrolley.GOODS_ID, comboGoodsIds)
                    .eq(ScTrolley.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
            if (GoodsTypeEnum.UPGRADE.getCode().equals(request.getType())){
                if (scTrolley == null) {
                    request.setSourceGoodsId(comboGoodsIds.get(0));
                }else {
                    request.setSourceGoodsId(Objects.equals(scTrolley.getType(), GoodsTypeEnum.UPGRADE.getCode()) ? scTrolley.getSourceGoodsId() : scTrolley.getGoodsId());
                }
            }
        }else{ //加购商品
            scTrolley = scTrolleyService.getOne(new QueryWrapper<ScTrolley>()
                    .eq(ScTrolley.USER_ID, request.getUserId())
                    .eq(ScTrolley.GOODS_ID, request.getGoodsId())
                    .eq(ScTrolley.TYPE,request.getType())
                    .eq(ScTrolley.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        }
        if (scTrolley != null) {
            number = scTrolley.getNumber()+ number;
            if (number == 0) {
                scTrolleyService.removeById(scTrolley.getId());
            } else {
                scTrolley.setNumber(request.getType() == GoodsTypeEnum.COMBO.getCode() ? 1 : number);
                scTrolley.setType(request.getType());
                scTrolley.setSourceGoodsId(request.getSourceGoodsId());
                scTrolley.setGoodsId(scGoods.getId());
                scTrolley.setGoodsName(scGoods.getName());
            }
        }else {
            scTrolley = new ScTrolley();
            scTrolley.setUserId(request.getUserId());
            scTrolley.setGoodsId(request.getGoodsId());
            scTrolley.setSourceGoodsId(request.getSourceGoodsId());
            scTrolley.setType(request.getType());
            scTrolley.setGoodsName(scGoods.getName());
            scTrolley.setNumber(number);
            scTrolley.setCategoryId(scGoods.getCategoryId());
            scTrolley.setCategoryName(scCategoryService.getById(scGoods.getCategoryId()).getName());
        }
        scTrolleyService.saveOrUpdate(scTrolley);
    }

    @Override
    public List<TrolleyListResponse> goodsList(Long userId) {
        List<ScTrolley> trolleys = scTrolleyService.list(new QueryWrapper<ScTrolley>().eq(ScTrolley.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScTrolley.USER_ID, userId));
        log.info("用户={}的购物车信息={}", userId, trolleys);
        if(null == userId || trolleys.isEmpty()) return Collections.emptyList();

        Map<Long, List<ScTrolley>> trolleyMap = trolleys.stream().collect(Collectors.groupingBy(ScTrolley::getCategoryId));
        log.info("根据二级分类分组={}", trolleyMap);
        List<TrolleyListResponse> responses = new ArrayList<>();
        for (Map.Entry<Long, List<ScTrolley>> entry : trolleyMap.entrySet()) {
            Long categoryId = entry.getKey();
            TrolleyListResponse response = new TrolleyListResponse();
            response.setCategoryId(categoryId);
            responses.add(response);
            List<ScTrolley> trolleyList = entry.getValue();
            List<TrolleyListResponse.TrolleyGoods> goodsList = new ArrayList<>();
            for (ScTrolley trolley : trolleyList) {
                response.setCategoryName(trolley.getCategoryName());
                TrolleyListResponse.TrolleyGoods goods = new TrolleyListResponse.TrolleyGoods();
                goods.setId(trolley.getId());
                goods.setSelect(trolley.getOption());
                goods.setGoodsId(trolley.getGoodsId());
                goods.setGoodsName(trolley.getGoodsName());
                goods.setNumber(trolley.getNumber());
                goods.setType(trolley.getType());
                ScGoods scGoods = scGoodsService.getOne(new QueryWrapper<ScGoods>().eq(ScGoods.ID, goods.getGoodsId()).eq(ScGoods.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode())
                        .last("limit 1"));
                if (scGoods != null) {
                    goods.setLabel(scGoods.getLabel());
                    if (trolley.getType() == 1){
                        BigDecimal sourceGoodsPrice = scGoodsService.getById(trolley.getSourceGoodsId()).getSalePrice();
                        goods.setSalePrice(scGoods.getSalePrice().subtract(sourceGoodsPrice));
                    }else if(trolley.getType() == 0) {
                        goods.setSalePrice(BigDecimal.ZERO);
                    } else{
                        goods.setSalePrice(scGoods.getSalePrice());
                    }
                    goods.setStatus(scGoods.getStatus());
                    goods.setMainImg(scGoods.getMainImg());
                    goods.setSubCategoryId(scGoods.getSubCategoryId());
                    goodsList.add(goods);
                }
            }
            response.setGoodsList(goodsList);
        }
        return responses;
    }


    @Override
    public BigDecimal diffPrice(List<Long> goodsIds, Long userId) {
        BigDecimal diffPrice = BigDecimal.ZERO;
        if (CollUtil.isEmpty(goodsIds) || null == userId) return diffPrice;

        List<ScTrolley> scTrolleyList = scTrolleyService.list(new QueryWrapper<ScTrolley>().eq(ScTrolley.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScTrolley.USER_ID, userId)
                .in(ScTrolley.GOODS_ID, goodsIds).in(ScTrolley.TYPE, 1, 2));
        if (scTrolleyList.isEmpty()) return diffPrice;
        List<Long> allGoodsIds = Stream.concat(
                scTrolleyList.stream().map(ScTrolley::getGoodsId),
                scTrolleyList.stream().map(ScTrolley::getSourceGoodsId)
        ).filter(Objects::nonNull).collect(Collectors.toList());

        Map<Integer, List<ScTrolley>> trolleyMap = scTrolleyList.stream().collect(Collectors.groupingBy(ScTrolley::getType));

        Map<Long, BigDecimal> goodsPriceMap = scGoodsService.list(new QueryWrapper<ScGoods>().eq(ScGoods.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).in(ScGoods.ID, allGoodsIds).eq(ScGoods.STATUS, 1))
                .stream().collect(Collectors.toMap(ScGoods::getId, ScGoods::getSalePrice));
        for (Map.Entry<Integer, List<ScTrolley>> entry : trolleyMap.entrySet()) {
            Integer type = entry.getKey();
            List<ScTrolley> trolleys = entry.getValue();
            if (type == 1){//升级商品
                for (ScTrolley trolley : trolleys) {
                    BigDecimal goodsPrice = Optional.ofNullable(goodsPriceMap.get(trolley.getGoodsId())).orElse(BigDecimal.ZERO);
                    BigDecimal sourceGoodsPrice = Optional.ofNullable(goodsPriceMap.get(trolley.getSourceGoodsId())).orElse(BigDecimal.ZERO);
                    diffPrice = diffPrice.add(goodsPrice.subtract(sourceGoodsPrice));
                }
            }else if (type == 2){
                for (ScTrolley trolley : trolleys) {
                    BigDecimal goodsPrice = goodsPriceMap.get(trolley.getGoodsId());
                    diffPrice = diffPrice.add(goodsPrice == null ? BigDecimal.ZERO : goodsPrice.multiply(BigDecimal.valueOf(trolley.getNumber())));
                }
            }
        }

        return diffPrice;
    }

    @Override
    public Boolean select(Long id, String option) {
        return scTrolleyService.update(new UpdateWrapper<ScTrolley>().eq(ScTrolley.ID, id).set(ScTrolley.OPTION, option));
    }
}
